﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;

namespace Codemonk.Common.Data
{
    public class DbParameterBuilder
    {
        private List<DbParameter> p_list;

        private List<DbParameter> ParasList
        {
            get
            {
                if (p_list == null)
                    p_list = new List<DbParameter>();
                return p_list;
            }
        }

        public bool IsCheckParameter
        {
            get;
            set;
        }

        public DbProviderFactory Factory { get; set; }

        public int Count
        {
            get
            {
                return p_list == null ? 0 : p_list.Count;
            }
        }

        public DbParameterBuilder()
        {
        }

        public DbParameterBuilder(int capacity)
        {
            p_list = new List<DbParameter>(capacity);
        }

        public DbParameterBuilder(IEnumerable<DbParameter> source)
        {
            ParasList.AddRange(source);
        }

        private DbParameter CreateDbParameter()
        {
            if (Factory == null)
                throw new InvalidProgramException("Factory属性未初始化");
            return Factory.CreateParameter();
        }

        public DbParameterBuilder Add(DbParameter para)
        {
            if (para == null)
                throw new ArgumentException("参数para为null");
            CheckParameter(para);
            ParasList.Add(para);
            return this;
        }
        public DbParameterBuilder Add(string parameterName, DbType? type = null)
        {
            DbParameter para = CreateDbParameter();
            para.ParameterName = parameterName;
            if (type.HasValue)
            {
                para.DbType = type.Value;
            }
            return Add(para);
        }
        public DbParameterBuilder Add(string parameterName, int size, DbType? type = null)
        {
            DbParameter para = CreateDbParameter();
            para.ParameterName = parameterName;
            para.Size = size;
            if (type.HasValue)
            {
                para.DbType = type.Value;
            }
            return Add(para);
        }
        public DbParameterBuilder Add(string parameterName, object value, int size, DbType? type = null)
        {
            DbParameter para = CreateDbParameter();
            para.ParameterName = parameterName;
            para.Value = value;
            para.Size = size;
            if (type.HasValue)
            {
                para.DbType = type.Value;
            }
            return Add(para);
        }
        public DbParameterBuilder Add(string parameterName, object value, int size, ParameterDirection direction, bool isNullable, string sourceColumn, DbType? type = null, DataRowVersion sourceVersion = DataRowVersion.Default)
        {
            DbParameter para = CreateDbParameter();
            para.ParameterName = parameterName;
            para.Value = value;
            para.Value = size;
            para.Direction = direction;
            para.SourceColumn = sourceColumn;
            para.SourceVersion = sourceVersion;
            if (type.HasValue)
            {
                para.DbType = type.Value;
            }
            return Add(para);
        }

        public DbParameterBuilder SetValue(string parameterName, object value)
        {
            var paras = ParasList;
            DbParameter item = null;
            foreach (var para in paras)
            {
                if (para.ParameterName.Equals(parameterName, StringComparison.Ordinal))
                {
                    item = para;
                    break;
                }
            }
            if (item != null)
                item.Value = value;
            return this;
        }
        public DbParameterBuilder SetValue(int index, object value)
        {
            var paras = ParasList;
            if (index > Count)
                throw new IndexOutOfRangeException("参数index越界");
            paras[index].Value = value;
            return this;
        }
        public DbParameterBuilder SetValue(object value)
        {
            if (Count > 0)
                ParasList[Count - 1].Value = value;
            return this;
        }
        public DbParameterBuilder SetSize(string parameterName, int size)
        {
            if (size < 0)
                throw new ArgumentException("size不能小于0");
            var paras = ParasList;
            DbParameter item = null;
            foreach (var para in paras)
            {
                if (para.ParameterName.Equals(parameterName, StringComparison.Ordinal))
                {
                    item = para;
                    break;
                }
            }
            if (item != null)
                item.Size = size;
            return this;
        }
        public DbParameterBuilder SetSize(int index, int size)
        {
            if (size < 0)
                throw new ArgumentException("size不能小于0");
            var paras = ParasList;
            if (index > Count)
                throw new IndexOutOfRangeException("参数index越界");
            paras[index].Size = size;
            return this;
        }
        public DbParameterBuilder SetSize(int size)
        {
            if (size < 0)
                throw new ArgumentException("size不能小于0");
            if (Count > 0)
                ParasList[Count - 1].Size = size;
            return this;
        }
        public DbParameterBuilder Set(Action<DbParameter> settet)
        {
            if (Count > 0)
                settet(ParasList[Count - 1]);
            return this;
        }

        private void CheckParameter(DbParameter para)
        {
            if (IsCheckParameter)
            {
                if (Count > 0)
                {
                    var _para = ParasList[0];
                    if (_para.GetType() != para.GetType())
                        throw new ArgumentException("传入参数类型和当前类型不相同");//空名称
                }
                InnerCheckParameterName(para.ParameterName);
            }
        }
        private void InnerCheckParameterName(string parameterName)
        {
            if (string.IsNullOrEmpty(parameterName))
                throw new ArgumentException("参数parameterName为空");//空名称
            var paras = ParasList;
            DbParameter item = null;
            foreach (var para in paras)
            {//已经有相同命名
                if (para.ParameterName.Equals(parameterName, StringComparison.Ordinal))
                {
                    item = para;
                    break;
                }
            }
            if (item != null)
                throw new ArgumentException("已经存在同名参数");
        }

        public DbParameterBuilder AddRange(IEnumerable<DbParameter> paras)
        {
            ParasList.AddRange(paras);
            return this;
        }

        public DbParameterBuilder Union(DbParameterBuilder helper)
        {
            if (helper != null && helper.p_list != null)
            {
                var paras = helper.p_list;
                var myParas = ParasList;
                var isFind = false;
                foreach (var para in paras)
                {
                    if (myParas.Contains(para))
                        continue;
                    isFind = false;
                    foreach (var p in myParas)
                    {
                        if (p.ParameterName.Equals(para.ParameterName, StringComparison.Ordinal))
                        {
                            isFind = true;
                            break;
                        }
                    }
                    if (isFind)
                        continue;
                    ParasList.Add(para);
                }
            }
            return this;
        }

        public DbParameterBuilder Remove(DbParameter para)
        {
            ParasList.Remove(para);
            return this;
        }

        public DbParameterBuilder Remove(string parameterName)
        {
            var paras = ParasList;
            DbParameter item = null;
            foreach (var para in paras)
            {
                if (para.ParameterName.Equals(parameterName, StringComparison.Ordinal))
                {
                    item = para;
                    break;
                }
            }
            if (item != null)
                paras.Remove(item);
            return this;
        }

        public DbParameterBuilder Clear()
        {
            ParasList.Clear();
            return this;
        }

        public IDataParameter[] ToArray()
        {
            var count = Count;
            if (count == 0)
                return null;
            IDataParameter[] ret = new IDataParameter[count];
            for (int i = 0; i < count; i++)
                ret[i] = ParasList[i];
            return ret;
        }

        public DbParameter[] ToDbParameterArray()
        {
            var count = Count;
            if (count == 0)
                return null;
            return ParasList.ToArray();
        }

        public IDbCommand AttachCommand(IDbCommand cmd)
        {
            if (cmd == null)
                throw new ArgumentException("参数cmd不能为空");
            var count = Count;
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                    cmd.Parameters.Add(ParasList[i]);
            }
            return cmd;
        }

        public static DbParameterBuilder operator +(DbParameterBuilder h1, DbParameterBuilder h2)
        {
            if (h1 == null)
                throw new ArgumentException("参数h1为null");
            return h1.Union(h2);
        }

        public static DbParameterBuilder operator -(DbParameterBuilder h1, DbParameter para)
        {
            if (h1 == null)
                throw new ArgumentException("参数h1为null");
            return h1.Remove(para);
        }

        public static DbParameterBuilder operator -(DbParameterBuilder h1, string parameterName)
        {
            if (h1 == null)
                throw new ArgumentException("参数h1为null");
            return h1.Remove(parameterName);
        }

        public static DbParameterBuilder operator +(DbParameterBuilder h1, string parameterName)
        {
            if (h1 == null)
                throw new ArgumentException("参数h1为null");
            return h1.Add(parameterName);
        }

        public static DbParameterBuilder operator +(DbParameterBuilder h1, DbParameter para)
        {
            if (h1 == null)
                throw new ArgumentException("参数h1为null");
            return h1.Add(para);
        }

        public static DbParameterBuilder operator +(DbParameterBuilder helper, IEnumerable<DbParameter> value)
        {
            if (helper == null)
                throw new ArgumentException("参数helper为null");
            return helper.AddRange(value);
        }

        public static implicit operator DbParameterBuilder(List<DbParameter> value)
        {
            var helper = new DbParameterBuilder();
            return helper.AddRange(value);
        }

        public static implicit operator DbParameterBuilder(DbParameter[] value)
        {
            var helper = new DbParameterBuilder();
            return helper.AddRange(value);
        }
    }
}
